home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / ease-3.5 / cfc / cfc.c next >
Encoding:
C/C++ Source or Header  |  1991-10-15  |  43.5 KB  |  1,889 lines

  1. #ifndef lint
  2. static char RCSid[] = "$Header: /tmp_mnt/home/kreskin/u0/barnett/Src/Ease/ease/cfc/RCS/cfc.c,v 3.3 1991/09/09 16:34:44 barnett Exp $";
  3. #endif
  4.  
  5. /*
  6.  * $Log: cfc.c,v $
  7.  * Revision 3.3  1991/09/09  16:34:44  barnett
  8.  * Bug fixes. Better handling of those $? conditionals.
  9.  *
  10.  * Revision 3.2  1991/05/16  10:49:33  barnett
  11.  * Support for IDA databases
  12.  * More tolerant handling of unusual conditions
  13.  * more bug fixes
  14.  *
  15.  * Revision 3.0  1991/02/22  19:33:07  barnett
  16.  * Many enhancements for IDA and HP sendmail.cf files
  17.  *
  18.  * Revision 2.2  1991/02/21  19:19:34  barnett
  19.  * Fixed several bugs:
  20.  *     Multiple ifsets on one line
  21.  *     Better handling of # in comments
  22.  *     Support for escaping a '* and /' in a comment field
  23.  *
  24.  * Revision 2.1  1990/01/30  11:38:10  jeff
  25.  * Enhancements by Bruce Barnett 89/1/23:
  26.  *    - Added some enhancements for SunOS 4.0 and Ultrix 3.0
  27.  *    - And a log of unusual grammar constructs
  28.  *
  29.  * Revision 2.0  88/06/15  15:16:48  root
  30.  * Baseline release for net posting. ADR.
  31.  * 
  32.  * Revision 1.6  88/06/10  13:45:16  root
  33.  * Fix originally from Raymond A. Schnitzler (ras@sabre.bellcore.com) to
  34.  * add the (undocumented) 'P' option which sets the Postmaster address for
  35.  * receiving cc's of bad mail. ADR.
  36.  * 
  37.  * Revision 1.5  88/01/21  16:18:13  root
  38.  * Eliminated Rutgers-ism, linted, smartened Mailer Argv handling. ADR.
  39.  * 
  40.  * Revision 1.4  88/01/21  15:57:52  root
  41.  * Added the 'y' factor; missed it last time. ADR.
  42.  * 
  43.  * Revision 1.3  87/04/08  10:23:02  root
  44.  * Small bug fixes, compatibility option added, also warnings for
  45.  * unrecognized flags and options. ADR.
  46.  * 
  47.  * Revision 1.2  87/02/18  15:26:39  root
  48.  * Fix to recognize multidigit ruleset numbers in $> (calls) in RHS. ADR.
  49.  * 
  50.  * Revision 1.1  87/02/16  15:25:00  arnold
  51.  * Initial revision
  52.  * 
  53.  * Revision 1.1  87/02/16  15:25:00  arnold
  54.  * Initial revision
  55.  * 
  56.  */
  57.  
  58. /*
  59.  * cfc.c
  60.  *
  61.  * Sendmail cf file compiler.
  62.  * Reads a raw sendmail.cf file and produces ease source.
  63.  *
  64.  * There are very few comments in this source. You will need both the
  65.  * "Sendmail Installation and Operation Guide" and the paper on Ease
  66.  * to really understand this.
  67.  *
  68.  * Arnold Robbins
  69.  * Emory University Computing Center
  70.  * 2/87
  71.  */
  72.  
  73. #include <stdio.h>
  74. #include <ctype.h>
  75.  
  76. char buffer[BUFSIZ];
  77. int line = 0;
  78. int inruleset = 0;
  79.  
  80. extern char *macro ();        /* convert sendmail to ease macro names */
  81. extern char *mflags ();        /* convert sendmail to ease mailer flag names */
  82. extern char *optionname ();    /* convert sendmail to ease option names */
  83. extern char *delivoption ();    /* delivery options */
  84. extern char *handle_option ();    /* handling options */
  85.  
  86. extern char *ngets ();        /* buffered gets () routine */
  87. extern void ungets ();        /* put a buffer back for getting */
  88.  
  89. #define endruleset()    if (inruleset) { inruleset = 0; printf ("\t}\n"); }
  90.  
  91. int compat = 0;            /* complain about new 4.3 options & flags */
  92. int undoc = 0;            /* complain about undocumented options, flags */
  93. int ida = 0;            /* IDA sendmail options  */
  94. int sunos  = 0;            /* Special parsing for SunOS - bgb */
  95. int DECos  = 0;            /* Special parsing for Ultrix - bgb */
  96.                 /* NOTE: can't use 'ultrix' cause of cpp */
  97. int hpos = 0;            /* HP/UX */
  98.  
  99. char *classes = 0;            /* list of classes defined */
  100. main (argc, argv)
  101. int argc;
  102. char **argv;
  103. {
  104.     extern int getopt ();
  105.     extern int optind;
  106.     extern char *optarg;
  107.     int i,c;
  108.  
  109.     while ((c = getopt (argc, argv, "icdhusC:")) != EOF) {
  110.         switch (c) {
  111.         case 'c':
  112.             compat = 1;
  113.             break;
  114.         case 'u':
  115.             undoc = 1;
  116.             break;
  117.         case 's':
  118.             sunos = 1;
  119.             break;
  120.         case 'd':
  121.             DECos = 1;
  122.             break;
  123.         case 'i':
  124.             ida = 1;
  125.             break;
  126.         case 'h':
  127.             hpos = 1;
  128.             break;
  129.             case 'C':
  130.             classes = optarg;
  131.             break;
  132.         case '?':
  133.         default:
  134.             fprintf (stderr, "usage: %s [ -[ids] ] [ -c ] [ -u ] [-C classes ]\n", argv[0]);
  135.             break;
  136.         }
  137.     }
  138.  
  139.     if (optind < argc)
  140.         fprintf (stderr,
  141.             "warning: ignoring non-flag command line arguments\n");
  142.  
  143.     printf ("/***********************************************************/\n");
  144.     printf ("/* This ease file generated by cfc version $Revision: 3.3 $*/\n");
  145.     printf ("/* automatically from a sendmail.cf file                   */\n");
  146.     printf ("/* It may need to be edited before feeding to ease.        */\n");
  147.     printf ("/***********************************************************/\n");
  148.     /* let's generate something that might work */
  149.     printf ("bind \n");
  150.     for (i=0;i<=29;i++) 
  151.       printf ("\tRULESET_%d = ruleset %d;\n",i,i);
  152.     /* SunOS uses ruleset 30. Other sendmails only support S0 to S29 */
  153.     if (sunos)
  154.       printf ("\tRULESET_30 = ruleset 30;\n");    
  155.  
  156.     /*
  157.      * For perfection, everything but the comment and rule cases
  158.      * should do an endruleset (), but practically speaking, it is
  159.      * usually only the mailer new ruleset definitions that end a
  160.      * previous ruleset. Occasionally a macro, too.
  161.      * Also class definitions - BGB
  162.      */
  163.  
  164.     while (ngets (buffer) != NULL)
  165.     {
  166.         line++;
  167.         switch (buffer[0]) {
  168.         case '#':
  169.             comment ();
  170.             continue;    /* skip code to end ruleset */
  171.         case 'S':
  172.             endruleset ();
  173.             ruleset ();
  174.             continue;    /* skip code to end ruleset */
  175.         case 'R':
  176.             rule ();
  177.             continue;    /* skip code to end ruleset */
  178.         case 'D':
  179.             endruleset ();
  180.             def ();
  181.             break;
  182.         case 'C':
  183.             endruleset ();
  184.             class ();
  185.             break;
  186.         case 'F':
  187.             endruleset ();
  188.             fileclass ();
  189.             break;
  190.         case 'M':
  191.             endruleset ();
  192.             mailer ();
  193.             break;
  194.         case 'H':
  195.             header ();
  196.             break;
  197.         case 'O':
  198.             option ();
  199.             break;
  200.         case 'T':
  201.             trusted ();
  202.             break;
  203.         case 'P':
  204.             precedence ();
  205.             break;
  206.         default:
  207.             other ();
  208.             continue;    /* skip code to end ruleset */
  209.         }
  210.         endruleset ();
  211.     }
  212.     endruleset ();        /* just in case */
  213.     exit (0);
  214.     /*NOTREACHED*/
  215. }
  216.  
  217. /* comment --- produce a comment */
  218.  
  219. comment ()
  220. {
  221.     static char format[] = "/* %s */\n";
  222.     register int i = strlen (buffer) - 1;
  223.     register int j;
  224.     /* try to be semi-intelligent about comments */
  225.  
  226.     /* if a blank line, keep as a blank line */
  227.     if (buffer[1] == '\0')
  228.         printf ("\n");
  229.     else { /* non-blank comment */
  230.         j=1;
  231.         printf("/*");
  232.         /* print ######## as /********* */
  233.         while (buffer[j] == '#') {
  234.         j++;
  235.         printf("*");
  236.         }
  237.         /* print the rest of the line */
  238.         while (buffer[j] != '\0') {
  239.         switch (buffer[j]) {
  240.           case '#':
  241.             /* convert ### to *** */
  242.             if (buffer[j+1] == '\0') {
  243.             printf("*");
  244.             } else if (buffer[j+1] == '#') /* a string of #### */
  245.               while (buffer[j] == '#' && buffer[j+1] != '\0') {
  246.               printf("*");
  247.               j++;
  248.               }
  249.             else printf("#");
  250.             break;
  251.           case '*':
  252.             if (buffer[j+1] == '/') { 
  253.             printf("*\\/");
  254.             j++;
  255.             } else printf("*");
  256.             break;
  257.           default:
  258.             printf("%c", buffer[j]);
  259.             break;
  260.         }
  261.         j++;
  262.         } /* end while */
  263.         if ( buffer[j-2] == '#' && buffer[j-1] == '#')
  264.           printf("*/\n");
  265.         else if ( buffer[j-2] != '#' && buffer[j-1] == '#')
  266.           printf("*/\n");
  267.         else if ( buffer[j-1] == ' ' || buffer[j-1] == '\t')
  268.           printf("*/\n");
  269.         else 
  270.           printf(" */\n");
  271.     } /* end of non-blank */
  272.     }
  273.  
  274. /* ruleset --- name a ruleset */
  275.  
  276. ruleset ()
  277. {
  278.     static int first = 1;
  279.     register char *cp = buffer + 1;
  280.     int i;
  281.  
  282.     if (first)
  283.     {
  284.         first = 0;
  285.         printf ("\n/* These are sample field definitons (cfc) */\n");
  286.         printf ("\nfield\n\tzero_or_more : match (0*);\n");
  287.         printf ("\tone_or_more : match (1*);\n");
  288.         printf ("\texactly_one : match (1);\n");
  289.         if (classes && *classes ) {
  290.             printf("\t/* defining classes %s */\n",classes);
  291.             for (i=0;*(classes+i);i++) {
  292.             printf ("\tany_in_%c : match (1) in %c;\n",*(classes+i),*(classes+i));
  293.             printf ("\tany_not_in_%c : match (0) in %c;\n",*(classes+i),*(classes+i));
  294.             }
  295.         }
  296.         /* let's make the default configuration nicer for SunOS - bgb */
  297.         if (DECos || ida  || hpos ) {
  298.             printf ("\tany_in_myhostname : match (1) in c_myname;\n");
  299.         }
  300.         if (sunos) {
  301. /*            printf ("\tany_in_V : match (1) in V;\n");
  302.             printf ("\tany_not_in_V : match (0) in V;\n"); */
  303.             printf ("/*\tany_in_map_? : match (1) map ?;\t*/\n");
  304.             printf ("/*\tany_not_in_map_? : match (0) map ?;\t*/\n");
  305.             printf ("\tany_in_etc_hosts : match  host;\n");
  306.             printf ("\tany_in_mydomainname : match (1) in c_mydomain;\n");
  307.             printf ("\tany_in_myhostname : match (1) in c_myname;\n");
  308.         } 
  309.     }
  310.  
  311.     printf ("ruleset\n\tRULESET_");
  312.     while (cp && *cp && ! isspace (*cp))
  313.     {
  314.         putchar (*cp);
  315.         cp++;
  316.     }
  317.  
  318.     printf (" {");
  319.     if (*cp)
  320.         printf ("\t/* %s */", cp);
  321.     putchar ('\n');
  322.     inruleset++;
  323. }
  324.  
  325. /* rule --- print out a rule */
  326.  
  327. rule ()
  328. {
  329.     register char *cp = buffer + 1;
  330.     register char *cp2;
  331.     register int com = 0;
  332.  
  333.     /* first, split it up into LHS, RHS, COMMENT */
  334.  
  335.     while (cp && *cp && *cp != '\t')
  336.         cp++;
  337.     if (!*cp) {
  338.         fprintf(stderr,
  339.             "Unexpected EOL when expecting right hand side of rule\n");
  340.         lhs(buffer+1);
  341.         printf("\n\tMissingRightHandSide();\n");
  342.         return;
  343.     }
  344.     *cp = '\0';
  345.  
  346.     cp++;
  347.     while (cp && *cp && *cp == '\t')
  348.         cp++;
  349.     cp2 = cp;
  350.     while (cp && *cp && *cp != '\t')
  351.         cp++;
  352.     if (*cp == '\t' && cp[1])
  353.     {
  354.         *cp = '\0';
  355.         com++;
  356.         cp++;
  357.         while (cp && *cp && *cp == '\t')
  358.             cp++;
  359.     }
  360.  
  361.     /* now print */
  362.     lhs (buffer + 1);    /* left hand side */
  363.     if (com)
  364.         printf ("\t/* %s */", cp);
  365.     putchar ('\n');
  366.     rhs (cp2);        /* right hand side */
  367. }
  368.  
  369. /* lhs --- left hand side of a production */
  370.  
  371. lhs (text)
  372. char *text;
  373. {
  374.     register char *cp = text;
  375.     register int conditional = 0;
  376.     register int quoting = 0;
  377.     register int open = 0;
  378.     int    ifset = 0;
  379.  
  380.     printf ("\tif (");
  381.     for (; *cp; cp++)
  382.     {
  383.         switch (*cp) {
  384.         case '$':
  385.             if (quoting)
  386.             {
  387.                 quoting = 0;
  388.                 putchar ('"');
  389.             }
  390.             switch (*++cp) {
  391.             case '*':
  392.                 printf (" zero_or_more ");
  393.                 break;
  394.             case '+':
  395.                 printf (" one_or_more ");
  396.                 break;
  397.             case '-':
  398.                 printf (" exactly_one ");
  399.                 break;
  400.             case '=':
  401.                 switch(*++cp) {
  402.                   case 'w':
  403.                     if (sunos || ida || DECos ) {
  404.                     printf (" any_in_myhostname ");
  405.                     break;
  406.                     } /* else fall through */
  407.                   case 'm':
  408.                     if (sunos ) {
  409.                     printf (" any_in_mydomainname ");
  410.                     break;
  411.                     } /* else fall through */
  412.                     default :
  413.                     printf (" any_in_%c ", *cp);
  414.                   }
  415.                 break;
  416.                 case '%' :
  417.                    /* YP map for SunOS */
  418.                    if ((cp+1) && sunos && (*(cp +1) == 'y') ) {
  419.                    printf (" any_in_etc_hosts"); ++cp;
  420.                    } else {
  421.                    printf (" any_in_map_%c", *++cp);
  422.                    }
  423.                    break;
  424.             case '~':
  425.                 printf (" any_not_in_%c ", *++cp);
  426.                 break;
  427.             case '?':
  428.                 printf (" ifset (%s, ", macro (*++cp));
  429.                 conditional++;ifset++;
  430.                 break;
  431.             case '|':
  432.                 if ( ! conditional) complain("in left hand side of rule, found a '$|' without a previous '$?'");
  433.                 if ( ifset) {
  434.                     /* I don't think I have to output a ", " */
  435.                     /* but let's test */
  436.                     if ( quoting ) 
  437.                       printf("\", \""); 
  438.                     else
  439.                       printf(", ");
  440.                 } else {
  441.                     complain("in left hand side of rule, found a '$|' without a previous '$?'");
  442.                     putchar (',');
  443.                 }
  444.                 break;
  445.             case '{':
  446.                 printf("ypalias (");    /* Ultrix */
  447.                 open++;
  448.                 break;
  449.             case '"':
  450.                 printf("yppasswd (");    /* Ultrix */
  451.                 open++;
  452.                 break;
  453.             case '.':
  454.                 putchar (')');
  455.                 conditional--;ifset--;
  456.                 break;
  457.             case '#':
  458.                 /* IDA does something strange with this */
  459.                 printf("resolved(");
  460.                 open++;
  461.                 break;
  462.             case '1':
  463.             case '2':
  464.             case '3':
  465.             case '4':
  466.             case '5':
  467.             case '6':
  468.             case '7':
  469.             case '8':
  470.             case '9':
  471.                 printf ("$%c", *cp);
  472.                 break;
  473.             default:
  474.                 if (quoting)
  475.                     printf ("${%s}", macro (*cp));
  476.                 else
  477.                     printf ("$%s", macro (*cp));
  478.                 break;
  479.             }
  480.             break;
  481.         default:
  482.             if (ispunct (*cp))
  483.             {
  484.                 if (quoting)    /* end a literal */
  485.                 {
  486.                     quoting = 0;
  487.                     putchar ('"');
  488.                 }
  489.                 /* else
  490.                     do nothing */
  491.             }
  492.             else
  493.             {
  494.                     /* start a literal - but ignore the first space  */
  495.                 if (*cp != ' ' && ! quoting)    
  496.                 {
  497.                     quoting = 1;
  498.                     putchar ('"');
  499.                 }
  500.                 /* else
  501.                     do nothing */
  502.             }
  503.             putchar (*cp);    /* print the character */
  504.             break;
  505.         }
  506.     }
  507.     if (quoting)
  508.         putchar ('"');
  509.     while (open--)
  510.         putchar (')');
  511.     if (conditional) { 
  512.         /* the lhs was missing a $. - let's add one automatically */
  513.         complain ("Expected '$.' on left hand side of rule - adding one anyway");
  514.         putchar (')');
  515.         conditional--;ifset--;
  516.     }
  517.     printf (")");
  518. }
  519.  
  520. /* rhs --- right hand side of a production */
  521.  
  522. rhs (text)
  523. char *text;
  524. {
  525.     register char *cp = text;
  526.     char *index ();
  527.     char *cp1;
  528.     register int open = 0;
  529.     register int conditional = 0;    /* true if in an ifset condition */
  530.     register int quoting = 0;    /* true if in a string */
  531.     register int ifset = 0;    /* true if in ifset(), like quoting */
  532.     register int needconcat = 0;    /* true if an $? on line (lookahead) */
  533.     register int didconcat = 0;    /* true if did the concat()    */
  534.     register int indbm = 0;    /* true if in IDA $( $) construct */
  535.     register int inalias = 0;    /* true if in IDA $(@ $) construct */
  536.     int    canon = 0;
  537.     int    diddefault = 0;
  538.  
  539.     printf ("\t\t");
  540.  
  541.     /* Need to handle this line */
  542.     /* R$+<@$=S>    $:$1<@$2>$?R<$R>$.    */
  543.     for(cp1=cp;*cp1;cp1++) {
  544.         if (*cp1 == '$' && (cp1+1) && *(cp1+1)== '?')
  545.           needconcat = 1;    /* there is an ifset on this line */
  546.     }
  547.     if (*cp == '$' && index ("#@:", cp[1]) != NULL)
  548.         ;    /* not the default */
  549.     else
  550.     {
  551.         printf ("retry (");
  552.         open++;
  553.     }
  554.  
  555.     for (; *cp; cp++)
  556.       {
  557.           switch (*cp) {
  558.         case '$':
  559.           if (quoting && ! ifset )
  560.             {
  561.             quoting = 0;
  562.             putchar ('"');
  563.             }
  564.           switch (*++cp) {
  565.             case '>':
  566.               printf ("RULESET_");
  567.               for (cp++; cp && *cp && isdigit (*cp); cp++)
  568.             putchar (*cp);
  569.               cp--;
  570.               printf (" (");
  571.               open++;
  572.               break;
  573.             case '[':
  574.               if (quoting) {
  575.               putchar('"');
  576.               quoting--;
  577.               }
  578.               printf (" canon (");
  579.               open++; canon++;
  580.               break;
  581.             case ']':
  582.               putchar (')');
  583.               open--;
  584.               if (diddefault) {
  585.               putchar (')');
  586.               diddefault--;
  587.               } else
  588.             canon--;
  589.               break;
  590.             case '{':
  591.               printf ("ypmap (%s, ", macro (*++cp)); /* sunos */
  592.               open++;
  593.               break;
  594.             case '}':
  595.               putchar (')');
  596.               open--;
  597.               break;
  598.             case '<':
  599.               printf ("program (%s, ", macro (*++cp)); /* HP/UX */
  600.               open++;
  601.               break;
  602.             case '?':
  603.               if (didconcat) {
  604.               printf ("\",");
  605.               needconcat = 0; /* don't need this */
  606.               }
  607.               printf ("ifset (%s, \"", macro (*++cp));
  608.               conditional++;
  609.               ifset++;
  610.               quoting++;
  611.               break;
  612.             case '|':
  613.               if ( ! conditional) complain("right side of rule - found '$|' without '$?'");
  614.               if ( ifset) {
  615.               printf("\", \"");
  616.               } else {
  617.               complain("right side of rule - found '$|' without '$?'");
  618.               putchar (',');
  619.               }
  620.               break;
  621.             case '.':
  622.               if (ifset && quoting ) {
  623.               putchar('"'); quoting--;
  624.               }
  625.               if (! ifset ) complain("right side of rule - found '$.' without '$?'");
  626.               putchar (')');
  627.               if (open) {
  628.               putchar(')');
  629.               open--;
  630.               }
  631.               conditional--;
  632.               ifset--;
  633.               break;
  634.             case '#':
  635.               parseresolve(cp);
  636.               goto out;    /* string is exhausted */
  637.               /* break; */
  638.             case '@':
  639.               if ( ! indbm) {
  640.               printf ("return (");
  641.               if (needconcat && cp+1 && cp+2 &&
  642.                   ! ((*(cp+1) == '$') && (*(cp+2) == '?'))){ 
  643.                   printf ("concat (\"");
  644.                   open++;didconcat++;
  645.               }
  646.               open++;
  647.               } else {
  648.                printf(", ");
  649. /*              printf("\", \""); */
  650.               }
  651.               break;
  652.             case ':':
  653.               if ( canon ) {
  654.               printf("default ( ");
  655.               canon--;diddefault++;
  656.               } else if ( indbm ) {
  657.               printf("default ( ");
  658.               indbm--;diddefault++;
  659.               } else {
  660.               printf ("next (");
  661.               if (needconcat && cp+1 && cp+2 &&
  662.                   ! ((*(cp+1) == '$') && (*(cp+2) == '?'))){ 
  663.                   printf ("concat (\"");
  664.                   open++;didconcat++;
  665.               }
  666.               open++;
  667.               } 
  668.               break;
  669.             case '(':
  670.               printf((*(++cp) == '@')
  671.                  ? " alias("        /* IDA alias lookup */
  672.                  : " dbm($%c, "    /* IDA database lookup */
  673.                  , *cp);
  674.               indbm++;
  675.               open++;
  676.               break;
  677.             case ')':
  678.               putchar (')');
  679.               open--;
  680.               if (diddefault) {
  681.               putchar (')');
  682.               diddefault--;
  683.               }
  684.               else
  685.                 indbm--;
  686.               break;
  687.             case '&':
  688.               printf(" eval(%s) ",macro(*(++cp)));
  689.               break;
  690.             case '1':
  691.             case '2':
  692.             case '3':
  693.             case '4':
  694.             case '5':
  695.             case '6':
  696.             case '7':
  697.             case '8':
  698.             case '9':
  699.               printf ("$%c", *cp);
  700.               break;
  701.             default:
  702.               if (ifset ) {
  703.               if (quoting)
  704.                 printf ("${%s}", macro (*cp));
  705.               else
  706.                 printf ("$%s", macro (*cp));
  707.               } else { /* not in ifset() */
  708.               if (quoting)
  709.                 printf ("${%s}", macro (*cp));
  710.               else 
  711.                 printf ("$%s", macro (*cp));
  712.               }
  713.               break;
  714.           }
  715.           break;         /* not a character that starts with a $ */
  716.         default:
  717.           if ( ifset  && quoting ) {
  718.               putchar(*cp);
  719.           } else if (ifset  && ! quoting) {
  720.               if ( ispunct (*cp)) {
  721.               putchar('"');quoting++;
  722.               } 
  723.               putchar(*cp); 
  724.           } else {    /* not ifset */
  725.               if (ispunct (*cp))
  726.             {
  727.                 if (quoting )    /* end a literal */
  728.                   {
  729.                   quoting = 0;
  730.                   putchar ('"');
  731.                   }
  732.                 /* else
  733.                    do nothing */
  734.             } else  {
  735.                 if (*cp != ' ' && ! quoting)    /* start a literal */
  736.                   {
  737.                   quoting = 1;
  738.                   putchar ('"');
  739.                   }
  740.                 /* else
  741.                    do nothing */
  742.             }
  743.               putchar (*cp);    /* print the character */
  744.           }
  745.           break;
  746.           }
  747.       } /* end of for */
  748. out:
  749.     if (quoting)
  750.         putchar ('"');
  751.     while (open--)
  752.         putchar (')');
  753.     printf (";\n");
  754.     if (conditional)
  755.         die ("rhs - $? without $.");
  756. }
  757. /* parseresolve - parse this mailer/host/user mess */
  758. parseresolve(cp)
  759. char    *cp;
  760. {
  761.     int quoting = 0;
  762.     int open = 0;
  763.     int ifset = 0;
  764.     char *addrops;
  765.     addrops = ".:;%@!=/[]?#^,<>$"; /* should be defined from input file */
  766.     printf ("resolve (mailer (");
  767.     /* this is a simple (idiotic) parser (hack) that scans the right
  768.        hand side of a $# rule
  769.        The format is usually
  770.        "$# mailer $@ host $: user" or
  771.        "$# mailer $: user"  or
  772.        "$# mailer $: something with a $macro"  or
  773.        "$# $M $: user"  or
  774.        "$# $1 "   (IDA sendmail )
  775.        
  776.        Note that there may be special constructs
  777.        in the host field, i.e.
  778.        "$1", "[$2]", "$w", or "$K".
  779.        and in the user field. Esp. in the error mailer:
  780.        "$1 < @$2 > $4",  or
  781.        "Never heard of host $2 in domain $m "
  782.        "$n" which should become -> "$m_daemon"
  783.        */
  784.     /* pointing to '#' */
  785.     cp++;
  786.     while( *cp == ' ') cp++; /* skip blanks */
  787.     /* output any character not a '$' */
  788.     while (cp && *cp && *cp != '$' ) {
  789.     /* skip spaces in the mailer field */
  790.     if ( *cp != ' ' ) putchar(*cp); 
  791.     cp++;
  792.     }
  793.   parsehost:
  794.     while (cp && *cp && *cp == ' ') cp++;    /* advance to non-blank */
  795.     if (!cp || !*cp ) goto out;
  796.     /* currently pointing to a "$" */
  797.     /* we may now be pointing to:
  798.        $@ - the host name
  799.        $: - the user
  800.        or a macro
  801.        or nothing?! (*cp == 0);
  802.        /* don't look at the '$' */
  803.     if (*cp == '$') {
  804.     cp++;    /* skip past $, expect a '@' */
  805.     } else {
  806.       fprintf(stderr,
  807.           "Error: found %c when expecting a '$' on line %d\n",
  808.           *cp,line);
  809.     }
  810.     if (!cp || !*cp ) goto out;
  811.     if (*cp  == ':') goto parseuser;
  812.     if (*cp == '?' ) {    /* handle $#$?G$@....$:...$|$@...$:...$. */
  813.     cp++;
  814.     printf ("),  ifset (%s,\n\t\t\t\t(", macro (*cp++));
  815.     ifset++;
  816.     while (cp && *cp && *cp == ' ') cp++;    /* advance to non-blank */
  817.     if ( *cp == '$') {
  818.         cp++;
  819.     } else {
  820.       fprintf(stderr,
  821.           "Error: found %c when expecting a '$' on line %d\n",
  822.           *cp,line);
  823.     }
  824.     }
  825.     if (*cp != '@' ) {
  826.     /* must be a macro name */
  827.     printf ("$%s",macro(*cp++));
  828.     /* now skip to the $@ */
  829. /*    if (!cp || !*cp ) goto out; */
  830.     while (cp && *cp && *cp == ' ') cp++;
  831.     if (!cp || !*cp ) goto out;
  832.     if (*cp == '$') cp++; 
  833.     else 
  834.       fprintf(stderr,
  835.           "Error: found %c when expecting a '$' on line %d\n",
  836.           *cp,line);
  837.     if (*cp == ':') goto parseuser;
  838.     if (*cp == '@') cp++;
  839.     else 
  840.       fprintf(stderr,
  841.           "Error: found %c when expecting a '@' on line %d\n",
  842.           *cp,line);
  843.     } else {
  844.     /* I did see the '@' of the $@ */
  845.     cp++;
  846.     }
  847.     /* print host name ($@host ) */
  848.     if (ifset)
  849.       printf (" host (");
  850.     else
  851.       printf ("),\n\t\t\t\thost (");
  852.     for (;cp && *cp;cp++) {
  853.     if (*cp != '$') { 
  854.         putchar (*cp);
  855.     } else {
  856.         /* it might be the $: */
  857.         if (!*(cp+1)) goto out;
  858.         if ( *(cp+1) == ':') {
  859.         cp++; /* parseuser expects ':' */
  860.         goto parseuser;
  861.         } else {
  862.         putchar(*cp++); /* print '$' */
  863.         printf("%s", macro(*cp)); /* and next */
  864.         }
  865.     }
  866.     }
  867.   parseuser:
  868.     printf ("),\n\t\t\t\tuser (");
  869.     /* *cp == ':', now look for user = $n */
  870.     /* maybe *cp == 0 */
  871.     if ( !*cp ) goto out;
  872.     if (*cp != ':' ) 
  873.       fprintf(stderr,
  874.           "Expected ':', found '%c' after '$' on line %d\n",*cp,line);
  875.     /* looking at the user string */
  876.     quoting = 0;
  877.     for (cp++; cp && *cp; cp++) {
  878.     if (quoting ) {
  879. /*        if (isalnum(*cp) || isspace(*cp)) { */
  880.         if (*cp == '"') {
  881.         printf("\\\"");    /* print "\" */
  882.         quoting++;
  883.         } else if (*cp == '\\') {
  884.         printf("\\");    /* print "\" and the next character */
  885.         putchar(*++cp);
  886.         } else if (!index(addrops,*cp))  {    
  887.         /* not one of those address characters */
  888.         putchar (*cp);
  889.         } else { /* maybe it's a dollar sign? */
  890.         quoting=0;
  891.         printf("\" %c",*cp);
  892.         if (*cp == '$') {
  893.             cp++;    /* This may not be used at all - but it can't hurt */
  894.             if (*cp == '>' ) { /* IDA sendmail */
  895.             cp++;
  896.             printf(" RULESET_");
  897.             while (cp && *cp && *cp >= '0' && *cp <= '9') putchar(*cp++);
  898.             printf("(");
  899.             open++;
  900.             } else {
  901.             printf("%s",macro(*cp));
  902.             }
  903.         }
  904.         }
  905.     } else {    /* not quoting */
  906.         if ( *cp == '$' ) {
  907.         cp++;
  908.         /* Could be $|, or $>, or $macro */
  909.         if (*cp == '>' ) { /* IDA sendmail */
  910.             cp++;
  911.             printf("retry (RULESET_");
  912.             while (cp && *cp && *cp >= '0' && *cp <= '9') putchar(*cp++);
  913.             printf("("); open++;
  914.             open++;
  915.         } else if ( *cp == '|') {
  916.             /* This is the middle of an ifset */
  917.             if ( ! ifset ) {
  918.             fprintf(stderr,
  919.                 "Found a '$|' in the user address without a '$?' on line %d\n",
  920.                 *cp,line);
  921.             cp++; /* ignore */
  922.             } else { /* I expected this */
  923.             printf(")),\n\t\t\t\t(");
  924.             cp++;
  925.             goto parsehost;
  926.             }
  927.         } else if ( *cp == '.') {
  928.             /* This is the END of an ifset */
  929.             if ( ! ifset ) {
  930.             fprintf(stderr,
  931.                 "Found a '$.' in the user address without a '$?' on line %d\n",
  932.                 *cp,line);
  933.             cp++; /* ignore */
  934.             } else { /* I expected this */
  935.             /* cp++; */ /* Don't do this, the for loop increments cp */
  936.             printf("))");
  937.             ifset = 0;
  938.             }
  939.         } else {
  940.             putchar ('$'); /* print $ */
  941.             printf("%s",macro(*cp)); /* and macro */
  942.         }
  943.         } else if (*cp && (index (addrops,*cp))) {
  944.         putchar(*cp);
  945.         } else if (*cp == '"') {
  946.         printf("\"\\\"");quoting++;    /* print "\" */
  947.         } else {
  948.         quoting = 1;
  949.         printf(" \"%c",*cp);
  950.         } 
  951.     } /* end of quoting/not quoting */
  952.     }
  953.     if (quoting) printf("\"");
  954.   out:
  955.     if (ifset) {
  956.     fprintf(stderr,
  957.         "EOL while expecting '$.' on line  %d\n",
  958.                 line);
  959.     ifset = 0;
  960.     }
  961.     while (open--) printf(")");
  962.     printf ("))");
  963. } /* end parseresolve () */
  964. /* def --- define a macro */
  965.  
  966. def ()
  967. {
  968.     register char *mac = buffer + 1, *value = buffer + 2;
  969.     register int conditional = 0;
  970.     register int concat = 0;
  971.     register int quote = 0;
  972.     register int ifset = 0;
  973.     
  974.  
  975.     printf ("macro\n\t%s = ", macro (*mac));
  976. /*    fprintf(stderr,"mac=%c, value=%s\n",*mac,value); */
  977.  
  978. /* This is tricky, we want the form:
  979.  *
  980.  *    Dq$g$?x$x$.
  981.  * to become
  982.  *  macro
  983.  *       m_defaddr = concat ("${m_sreladdr}", ifset (m_sname," (${m_sname})"));
  984.  * and
  985.  *      Dq$?x$x $.<$g>
  986.  * to become
  987.  *  macro
  988.  *       m_defaddr = concat (ifset (m_sname," (${m_sname})"),"<${m_sreladdr}>" );
  989.  *
  990.  * One problem is the form 
  991.  *    Dq$?x$x <$g>$|$g$.
  992.  *
  993.  *
  994.  */
  995.     concat = 0;
  996.     quote = 0;
  997.     conditional = 0;
  998.     ifset = 0;
  999.     if (! *value ) printf("\"\""); /* unusual error - just print " and let
  1000.                            the end of the loop after the while 
  1001.                            clean it up */
  1002.     while (*value)
  1003.     {
  1004.         switch (*value) {
  1005.         case '$':
  1006.             switch (*++value) {
  1007.             /* $:$?E$1%$2.dnet<@$E.LOCAL>$3$|$1<@$2.dnet>$3$. 
  1008.                Dq$?x$x <$g>$|$g$.
  1009.                Dq$?x$!x <$g>$|$g$.
  1010.                */
  1011.             case '?':
  1012.                     /* Another special case %$&*! 
  1013.                      * if the start of the string is $?, 
  1014.                  * but the end is NOT $., then we need a concat
  1015.                  */
  1016.                     if (*(value+strlen(value)-1) == '.' &&
  1017.                         *(value+strlen(value)-2) == '$') {
  1018.                     /* just use ifset with no concat */
  1019.                     printf ("ifset (%s, ", macro (*++value));
  1020.                     conditional++;ifset++;
  1021.                     /* Still need a quote character,
  1022.                        next characters might be a $!x */
  1023.                     if ((*(value+1) == '$') && (*(value+2) == '!')) {
  1024.                     value++;value++;
  1025.                     printf("\"${quote(%s)} ",macro(*++value));
  1026.                     quote++;
  1027.                     } else {
  1028.                     printf("\"");quote++;
  1029.                     }
  1030.                 } else {
  1031.                     printf ("concat( ifset (%s, \"", macro (*++value));
  1032.                     conditional++;quote++;concat++;ifset++;
  1033.                 }
  1034.                 break;
  1035.             case '|':
  1036.                 if ( ! conditional) die("def - $| without $?");
  1037.                 if ( ifset) {
  1038.                     printf("\", \"");
  1039.                 } else {
  1040.                     complain("Got $| when not in ifset\n");
  1041.                     putchar (',');
  1042.                 }
  1043.                 break;
  1044.             case '.':
  1045.                 if (quote) {
  1046.                     putchar('"');quote--;
  1047.                 }
  1048.                 putchar (')');
  1049.                 conditional--;ifset--;
  1050.                 /* not EOL, must be in concat(ifset( ,) */
  1051.                 if (*(value+1)) putchar(','); 
  1052.                 break;
  1053.                   case '!':    /* IDA sendmail  - this code never gets executed */
  1054.                 printf("quote("); concat++;
  1055.                 break;
  1056.                 default:
  1057.             /* see if *(value+1) == '$' and *(value+2) == '?' */
  1058.                 if (!concat && (strlen(value)>2) 
  1059.                     && (*(value+1) == '$')
  1060.                     && (*(value+2) == '?')) {
  1061.                     printf ("concat (\"${%s}\", ", macro (*value));
  1062.                     /* I'm gonna need a concat */
  1063.                     concat++;
  1064.                 } else {
  1065.                     if (!quote) {
  1066.                     printf("\"${%s}", macro (*value));
  1067.                     quote++;
  1068.                     } else {
  1069.                     printf ("${%s}", macro (*value));
  1070.                     }
  1071.                 }
  1072.                 break;
  1073.             }
  1074.             break;
  1075.             case '"' :
  1076.                 if (quote) {
  1077.                 printf ("\\\"");
  1078.             } else {
  1079.                 printf("\"\\\"");
  1080.                 quote++;
  1081.             }
  1082.             break;
  1083.         default:
  1084.             if ( ! quote ) {
  1085.                 putchar('"');
  1086.                 quote++;
  1087.             }
  1088.             putchar (*value);
  1089.             break;
  1090.         }
  1091.         value++;
  1092.     }
  1093.     if ( quote ) putchar('"');
  1094.     if (concat) {
  1095.         putchar (')');
  1096.         concat--;
  1097.     }
  1098.     printf (";\n");
  1099.     if (conditional)
  1100.         die ("def - $? without $.");
  1101. }
  1102.  
  1103. /* class --- define a class list */
  1104.  
  1105. class ()
  1106. {
  1107.     register char *name = buffer + 1, *value = buffer + 2;
  1108.     int  havepunct;
  1109.     char *s;
  1110.  
  1111.  
  1112.     printf ("class\n\t");
  1113.       switch (name[0]) {
  1114.         case 'w' :     printf("c_myname"); break;
  1115.         case 'm' :     if (sunos) { printf("c_mydomain"); break; }
  1116.           /* fall through if not SunOS */
  1117.         default:    printf("%c",name[0]);
  1118.       }
  1119.  
  1120.     printf (" = { ");
  1121.  
  1122.     while (value && *value && isspace (*value))
  1123.         value++;
  1124.  
  1125.     /* a class may be a series of punctuation characters e.g. IDA */
  1126.     /* also watch for spaces on the end of a line and avoid ',)' */
  1127.  
  1128.     while (value && *value)
  1129.     {
  1130.         /* get first field */
  1131.         /* look for first space or EOL */
  1132.         for (s=value,havepunct=0;*s && ! isspace (*s);s++)
  1133.           if (ispunct(*s)) havepunct = 1;
  1134.  
  1135.         /* field is from *value to *s  
  1136.            if there is a punctuation char, havepunt == 1 */
  1137.         if (havepunct) putchar('"');
  1138.         while (value < s ) {
  1139.         if (*value == '"') putchar('\\');     /* escape quotes */
  1140.         if (*value == '$' ) printf ("${%s}", macro (*++value));
  1141.         else putchar(*value);
  1142.         value++;
  1143.         }
  1144.         if (havepunct) putchar('"');
  1145.         /* if not EOL, put a comma there 
  1146.            but watch out for extra spaces..... 
  1147.  
  1148.            so scan over spaces, then look at the next character.
  1149.            If not EOL, print ", ". */
  1150.  
  1151.            while (value && *value && isspace(*value)) value++;
  1152.            if (*value && !isspace(*value)) printf (", ");
  1153.     }
  1154.     printf (" };\n");
  1155. }
  1156.  
  1157. /* fileclass --- define a class that is to be read from a file */
  1158.  
  1159. fileclass ()
  1160. {
  1161.     register char *name = buffer + 1, *value = buffer + 2;
  1162.  
  1163.     printf ("class\n\t%c = readclass (\"", *name);
  1164.     for (; *value && !isspace (*value); value++)
  1165.         putchar (*value);
  1166.     putchar ('"');
  1167.     while (value && *value && isspace (*value))
  1168.         value++;
  1169.     if (*value)
  1170.         printf (", \"%s\"", value);
  1171.     printf (");\n");
  1172. }
  1173.  
  1174. /* mailer --- convert a mailer specification */
  1175.  
  1176. mailer ()
  1177. {
  1178.     register char *cp = buffer + 1;
  1179.  
  1180.     printf ("mailer\n\t");
  1181.     for (; *cp != ','; cp++)
  1182.         putchar (*cp);
  1183.     cp++;
  1184.     printf (" {\n");    /* just did mailer name */
  1185.  
  1186. #define skipname()    cp++; while (cp && *cp && *cp != '=') cp++; cp++
  1187. #define value()        for (; cp && *cp && *cp != ','; cp++) putchar (*cp); cp++
  1188.  
  1189. loop:
  1190.     while (cp && *cp && isspace (*cp))
  1191.         cp++;
  1192.  
  1193.     printf ("\t\t");
  1194.     switch (*cp) {
  1195.     case 'A':
  1196.         skipname ();
  1197.         printf ("Argv = \"");
  1198.         for (; *cp && *cp != ','; cp++)
  1199.         {
  1200.             if (*cp == '$')    /* XXX: assume no conditionals */
  1201.                 printf ("${%s}", macro (*++cp));
  1202.             else if (*cp == '"')
  1203.                 printf ("\\\"");
  1204.             else
  1205.                 putchar (*cp);
  1206.         }
  1207.         cp++;    /* do manually what value does */
  1208.         putchar ('"');
  1209.         break;
  1210.  
  1211.     case 'E':
  1212.         skipname ();
  1213.         printf ("Eol = \"");
  1214.         value ();
  1215.         putchar ('"');
  1216.         break;
  1217.  
  1218.     case 'F':
  1219.         skipname ();
  1220.         printf ("Flags = { ");
  1221.         for (; *cp && *cp != ','; cp++)
  1222.         {
  1223.             printf ("%s", mflags (*cp));
  1224.             if (cp[1] && cp[1] != ',')
  1225.                 printf (", ");
  1226.         }
  1227.         cp++;    /* do manually what value does */
  1228.         printf (" }");
  1229.         break;
  1230.  
  1231.     case 'M':
  1232.         skipname ();
  1233.         printf ("Maxsize = \"");
  1234.         value ();
  1235.         putchar ('"');
  1236.         break;
  1237.  
  1238.     case 'P':
  1239.         skipname ();
  1240.         printf ("Path = \"");
  1241.         value ();
  1242.         putchar ('"');
  1243.         break;
  1244.  
  1245.     case 'R':
  1246.         skipname ();
  1247.         printf ("Recipient = RULESET_");
  1248.         /* IDA has ruleset/ruleset */
  1249.         for (; *cp && *cp != ',' && *cp != '/'; cp++) 
  1250.           putchar (*cp); 
  1251.         if (ida && cp && (*cp == '/' )) {
  1252.             putchar (*cp++);
  1253.             printf("RULESET_");
  1254.             value ();
  1255.         } else {
  1256.             cp++ ;
  1257.         }
  1258.         break;
  1259.  
  1260.     case 'S':
  1261.         skipname ();
  1262.         printf ("Sender = RULESET_");
  1263.         /* IDA has ruleset/ruleset */
  1264.         for (; *cp && *cp != ',' && *cp != '/'; cp++) 
  1265.           putchar (*cp); 
  1266.         if (ida && cp && (*cp == '/' )) {
  1267.             putchar (*cp++);
  1268.             printf("RULESET_");
  1269.             value ();
  1270.         } else {
  1271.             cp++ ;
  1272.         }
  1273.         break;
  1274.  
  1275.     case '\0':
  1276.         goto done;
  1277.     }
  1278.  
  1279.     if (cp[-1] && cp[-1] == ',')
  1280.     {
  1281.         printf (",\n");
  1282.         goto loop;
  1283.     }
  1284.     else
  1285.         putchar ('\n');
  1286.  
  1287. done:
  1288.     /* handle continuation lines */
  1289.     if (ngets (buffer) != NULL)
  1290.     {
  1291.         line++;
  1292.         if (buffer[0] == '\t')
  1293.         {
  1294.             cp = buffer;
  1295.             goto loop;
  1296.         }
  1297.         else
  1298.             ungets (buffer);
  1299.     }
  1300.     else
  1301.         ungets ((char *) NULL);
  1302.     
  1303.     printf ("\t};\n");
  1304.  
  1305. #undef value
  1306. #undef skipname
  1307. }
  1308.  
  1309. /* header --- define sendmail headers */
  1310.  
  1311. header ()
  1312. {
  1313.     register char *cp = buffer + 1;
  1314.     register int flags = 0;
  1315.     register int conditional = 0;
  1316.     register int concat = 0;    /* true if in a concat( */
  1317.     register int needcomma = 0;    /* true if a concat is needed */
  1318.     register int quote = 0;
  1319.     register int ifset = 0;        /* true if in a ifset 
  1320.                        (may be inside a concat) */
  1321.  
  1322.     printf ("header\n\t");
  1323.     if (*cp == '?')        /* header for mailers  with these flags */
  1324.     {
  1325.         flags++;
  1326.         printf ("for (");
  1327.         for (cp++; cp && *cp != '?'; cp++)
  1328.         {
  1329.             printf ("%s", mflags (*cp));
  1330.             if (cp[1] != '?')
  1331.                 putchar (',');
  1332.         }
  1333.         printf (") {\n\t\t");
  1334.         cp++;    /* skip final '?' */
  1335.     }
  1336.  
  1337.     printf ("define (\"");
  1338.     for (; *cp && ! isspace (*cp); cp++)
  1339.         putchar (*cp);
  1340.     /* skip over any spaces */
  1341.     while ( cp && *cp && isspace(*cp)) cp++;
  1342.         /* but if we are now at the end of the line, we must fake
  1343.        an entry for "" */
  1344.     if ( cp && *cp ) printf ("\", ");  /* don't print next " yet, see if it is a concat */
  1345.     else if (cp && ! *cp ) printf("\", \"\"");
  1346.     else if (!cp) {
  1347.         printf("\"");
  1348.         complain("I didn't expect this!\n");
  1349.     }
  1350.  
  1351.     quote = concat = conditional = ifset = needcomma = 0;
  1352. body:
  1353.     while (cp && *cp)
  1354.     {
  1355.         switch (*cp) {
  1356.         case '$':
  1357.             switch (*++cp) {
  1358.             case '?':
  1359.                 /* if we are in the middle of a quote, end it */
  1360.                 if (quote) {
  1361.                 printf("\"");quote--;needcomma=1;
  1362.                 }
  1363.                 /* if we are not in a concat, then start one */
  1364.                 if ( ! concat ) {
  1365.                 if (needcomma) printf(", ");
  1366.                 printf("concat (");
  1367.                 concat++;needcomma=0;
  1368.                 }  else { /* we are in a concat  */
  1369.                 if ( ifset ) { /* if in ifset(..) terminate */
  1370.                     printf("), concat ("); 
  1371.                     ifset--;needcomma=0;
  1372.                 } else {
  1373.                     /* otherwise - don't terminate the concat */
  1374.                     /* but add a comma to seperate the fields */
  1375.                     /* what do do if concat(X, */
  1376.                     /* if so, then don't put the comma */
  1377.                     /* instead - check needcomma */
  1378. /*                    printf(", "); */
  1379.                 }
  1380.                 }
  1381.                 if ( ifset ) {
  1382.                 complain("found '$?' before terminating previous '$?' with a '$.'");
  1383.                 }
  1384.                 if (needcomma) {
  1385.                 printf(", ");
  1386.                 needcomma=0;
  1387.                 }
  1388.                 printf ("ifset (%s, \"", macro (*++cp));
  1389.                 conditional++; quote++;ifset++;
  1390.                 break;
  1391.             case '|':
  1392.                 if (quote) {
  1393.                 putchar('"');quote--;
  1394.                 }
  1395.                 if ( ! conditional) complain("header - $| without $?");
  1396.                 if ( ifset) {
  1397.                 printf(", "); needcomma=0;
  1398.                 } else {
  1399.                 complain("Got '$|' without matching '$?'");
  1400.                 putchar (','); needcomma=0;
  1401.                 }
  1402.                 break;
  1403.             case '.':
  1404.                 if (quote) {
  1405.                 putchar('"');quote--;
  1406.                 }
  1407.                 if (!ifset ) {
  1408.                 complain("found '$.' without matching '$?'");
  1409.                 }
  1410.                 putchar (')');
  1411.                 conditional--;ifset--;
  1412.                 if (concat) {
  1413.                 /* this is messy - There may be more than one $? on a line */
  1414.                 /* and the line may continue on to the next line. */
  1415.  
  1416.                 if (*(cp+1)) { /* if there is more on the line */
  1417.                     putchar(')');concat--;
  1418.                     printf(", ");needcomma=0;
  1419.                 } else { 
  1420.                     /* may need to print a comma - delay decision */
  1421.                     /* see continuation line handler */
  1422.                     putchar(')');concat--;needcomma=1;
  1423.                 }
  1424.                 }
  1425.                 break;
  1426.             default: /* a $<letter> */
  1427.             /* see if *(cp+1) == '$' and *(cp+2) == '?' */
  1428.                 if (!concat && (strlen(cp)>2) 
  1429.                 && (*(cp+1) == '$')
  1430.                 && (*(cp+2) == '?')) {
  1431.                 if ( quote) {
  1432.                     printf("\", ");
  1433.                     quote--;needcomma=0;
  1434.                 }
  1435.                 printf ("concat (\"${%s}\", ", macro (*cp));
  1436.                 /* I'm in a concat */
  1437.                 concat++;
  1438.                 } else {
  1439.                 if (!quote) {
  1440.                     printf("\"${%s}", macro (*cp));
  1441.                     quote++;
  1442.                 } else {
  1443.                     printf ("${%s}", macro (*cp));
  1444.                 }
  1445.                 }
  1446.                 break;
  1447.             }
  1448.             break;
  1449.             case '"' :
  1450.             printf ("\\\"");
  1451.             break;
  1452.         default:
  1453.             if ( ! quote ) {
  1454.                 putchar('"');
  1455.                 quote++;
  1456.             }
  1457.             putchar (*cp);
  1458.             break;
  1459.         }
  1460.         cp++;
  1461.     }
  1462.  
  1463.     /* handle continuation lines */
  1464.     if (ngets (buffer) != NULL)
  1465.     {
  1466.         line++;
  1467.         if (buffer[0] == '\t')
  1468.         {
  1469.             if ( concat ) {
  1470.                 printf("), ");needcomma=0;
  1471.                 concat--;
  1472.             }
  1473.             if (needcomma) {
  1474.                 printf(", ");
  1475.                 needcomma=0;
  1476.             }
  1477.             if ( ! quote ) {
  1478.                 putchar('"');
  1479.                 quote++;
  1480.             }
  1481.             printf ("\\\n");
  1482.             cp = buffer + 1;
  1483.  
  1484.             goto body;
  1485.         }
  1486.         else
  1487.             ungets (buffer);
  1488.     }
  1489.     else
  1490.         ungets ((char *) NULL);
  1491.  
  1492.     if ( quote ) {
  1493.         putchar('"'); 
  1494.     }
  1495.     if (concat) {
  1496.         putchar(')');
  1497.         concat--;
  1498.     }
  1499.     printf (");\n");
  1500.  
  1501.     if (flags)
  1502.         printf ("\t};\n");
  1503.  
  1504.     if (conditional)
  1505.         die ("header translation  problem: $? without $.");
  1506. }
  1507.  
  1508. /* option --- translate a sendmail option to an ease option */
  1509.  
  1510. option ()
  1511. {
  1512.     register char *name = buffer + 1, *value = buffer + 2;
  1513.     char *newname;
  1514.     char *newvalue;
  1515.  
  1516.     printf ("options\n\t");
  1517.     if (*name == 'd') {    /* delivery */
  1518.         newvalue = delivoption (*value);
  1519.         if ( newvalue == NULL) {
  1520.         printf("/* Unknown value for delivery option           */\n");
  1521.         printf("/* Supplying the default value of d_background */\n");
  1522.         printf ("o_delivery = d_background ;\n" );
  1523.         } else
  1524.           printf ("o_delivery = %s;\n", newvalue);
  1525.     } else if (*name == 'e')    {    /* handling */
  1526.         newvalue = handle_option(*value);
  1527.         if (newvalue == NULL ) {
  1528.         printf("/* Unknown value for delivery option       */\n");
  1529.         printf("/* Supplying the default value of h_print  */\n");
  1530.         printf ("o_handling =  h_print ;\n");
  1531.         } else
  1532.           printf ("o_handling = %s;\n", newvalue);
  1533.     } else if (*name == 'K' ) {    /* IDA Keyed Database */
  1534.         printf("asm(\"OK%s\");\n", value);
  1535.     } else    {
  1536.         newname = optionname(*name);
  1537.         if (newname == NULL)
  1538.           printf("asm(\"O%c%s\");\n", *name, value);
  1539.         else
  1540.         printf ("%s = \"%s\";\n", optionname (*name), value);
  1541.     }
  1542. }
  1543.  
  1544. /* trusted --- define the list of trusted users */
  1545.  
  1546. trusted ()
  1547. {
  1548.     register char *cp = buffer + 1;
  1549.  
  1550.     if ( *cp && *cp == ' ') cp++; /* skip over spaces in the begining */
  1551.     while (cp && *cp)
  1552.     {
  1553.         if (isspace (*cp))
  1554.             *cp = ',';
  1555.         cp++;
  1556.     }
  1557.     printf ("trusted\n\t{ %s };\n", buffer+1);
  1558. }
  1559.  
  1560. /* precedence --- define the precedence of a message class */
  1561.  
  1562. precedence ()
  1563. {
  1564.     register char *cp = buffer + 1;
  1565.  
  1566.     printf ("precedence\n\t");
  1567.     for (; *cp && *cp != '='; cp++)
  1568.         putchar (*cp);
  1569.     printf (" = %s;\n", ++cp);
  1570. }
  1571.  
  1572. /* other --- not a sendmail control line */
  1573. /* it may also be a blank line           */
  1574.  
  1575. other ()
  1576. {
  1577.     printf ("%s\n", buffer);
  1578. }
  1579.  
  1580. die (routine)
  1581. char *routine;
  1582. {
  1583.     fprintf (stderr, "%s: malformed input line %d: fatal error\n",
  1584.             routine, line);
  1585.     exit (1);
  1586. }
  1587. complain (problem)
  1588. char *problem;
  1589. {
  1590.     fprintf (stderr, "Warning: malformed input line %d: %s\n",
  1591.             line, problem);
  1592.     fflush(stderr);
  1593.     fflush(stdout);
  1594.     }
  1595.  
  1596. /* macro --- return name for sendmail predefined macro */
  1597.  
  1598. char *macro (c)
  1599. char c;
  1600. {
  1601.     static char buf[2] = { '\0', '\0' };
  1602.  
  1603.     switch (c) {
  1604.     case 'a':    /* The origination date in Arpanet format */
  1605.         return ("m_odate");
  1606.  
  1607.     case 'b':    /* The current date in Arpanet format */
  1608.         return ("m_adate");
  1609.  
  1610.     case 'c':    /* The hop count */
  1611.         return ("m_hops");
  1612.  
  1613.     case 'd':    /* The date in UNIX (ctime) format */
  1614.         return ("m_udate");
  1615.  
  1616.     case 'e':    /* The SMTP entry message */
  1617.         return ("m_smtp");
  1618.  
  1619.     case 'f':    /* The sender (from) address */
  1620.         return ("m_saddr");
  1621.  
  1622.     case 'g':    /* The sender address relative to the recipient */
  1623.         return ("m_sreladdr");
  1624.  
  1625.     case 'h':    /* The recipient host */
  1626.         return ("m_rhost");
  1627.  
  1628.     case 'i':    /* The queue id */
  1629.         return ("m_qid");
  1630.  
  1631.     case 'j':    /* The official domain name for this site */
  1632.         return ("m_oname");
  1633.  
  1634.     case 'k':    /* The official domain name for this site */
  1635.         return ("m_uucpname");    /* IDA */
  1636.  
  1637.     case 'l':    /* The format of the UNIX from line */
  1638.         return ("m_ufrom");
  1639.  
  1640.     case 'm':    /* The Domain Name (SunOS) */
  1641.         if (sunos || ida ) {
  1642.             return ("m_domain");
  1643.         } else {
  1644.             buf[0] = c;
  1645.             return (buf);
  1646.         }
  1647.  
  1648.     case 'n':    /* The name of the daemon (for error messages) */
  1649.         return ("m_daemon");
  1650.  
  1651.     case 'o':    /* The set of "operators" in addresses */
  1652.         return ("m_addrops");
  1653.  
  1654.     case 'p':    /* Sendmail's pid */
  1655.         return ("m_pid");
  1656.  
  1657.     case 'q':    /* The default format of sender address */
  1658.         return ("m_defaddr");
  1659.  
  1660.     case 'r':    /* Protocol used */
  1661.         return ("m_protocol");
  1662.  
  1663.     case 's':    /* Sender's host name */
  1664.         return ("m_shostname");
  1665.  
  1666.     case 't':    /* A numeric representation of the current time */
  1667.         return ("m_ctime");
  1668.  
  1669.     case 'u':    /* The recipient user */
  1670.         return ("m_ruser");
  1671.  
  1672.     case 'v':    /* The version number of sendmail */
  1673.         return ("m_version");
  1674.  
  1675.     case 'w':    /* The hostname of this site */
  1676.         return ("m_sitename");
  1677.  
  1678.     case 'x':    /* The full name of the sender */
  1679.         return ("m_sname");
  1680.  
  1681.     case 'y':    /* The id of the sender's tty */
  1682.         return ("m_stty");
  1683.  
  1684.     case 'z':    /* The home directory of the recipient */
  1685.         return ("m_rhdir");
  1686.  
  1687.         case '"':    /* you can get a quote character in some macro definitions */
  1688.         return ("\\\"");
  1689.     default:
  1690.         if (!(isalpha(c) || isdigit(c))) /* if not a digit or letter */
  1691.           fprintf (stderr,
  1692.                "warning: expected letter as macro definition, found '%c' on line %d\n",
  1693.                c, line);
  1694.  
  1695.         buf[0] = c;
  1696.         return (buf);
  1697.     }
  1698. }
  1699.  
  1700. #define docompat(val)    if (compat) goto warn; else return (val)
  1701. #define dofundoc(val)    if (undoc) \
  1702. fprintf (stderr, "warning: undocumented flag '%c' used on line %d\n", c, line);\
  1703. return (val)
  1704.  
  1705. /* mflags --- convert sendmail mailer flags to ease names */
  1706.  
  1707. char *mflags (c)
  1708. char c;
  1709. {
  1710.     static char buf[2] = { '\0', '\0' };
  1711.     char tstring[100];
  1712.  
  1713.     switch (c) {
  1714.     case 'f':    return ("f_ffrom");
  1715.     case 'r':    return ("f_rfrom");
  1716.     case 'S':    return ("f_noreset");
  1717.     case 'n':    return ("f_noufrom");
  1718.     case 'l':    return ("f_locm");
  1719.     case 's':    return ("f_strip"); 
  1720.     case 'm':    return ("f_mult");
  1721.     case 'F':    return ("f_from");
  1722.     case 'D':    return ("f_date");
  1723.     case 'M':    return ("f_mesg");
  1724.     case 'x':    return ("f_full");    
  1725.     case 'P':    return ("f_return");    
  1726.     case 'u':    return ("f_upperu");    
  1727.     case 'h':    return ("f_upperh");    
  1728.     case 'H':    return ("f_mail11");    /* Ultrix 3.0 */
  1729.     case 'A':    return ("f_arpa");    
  1730.     case 'U':     return ("f_ufrom");
  1731.     case 'e':    return ("f_expensive");
  1732.     case 'X':    return ("f_dot");
  1733.     case 'L':    return ("f_llimit");    
  1734.     case 'p':    return ("f_retsmtp");    
  1735.     case 'I':    return ("f_smtp");    
  1736.     case 'C':    return ("f_addrw");    
  1737.     case 'E':    docompat ("f_escape");
  1738.     case 'R':    dofundoc ("f_rport");
  1739.     case 'B':    return ("f_bsmtp"); /* IDA sendmail */
  1740.     case 'V':    return ("f_relativize"); /* IDA sendmail */
  1741.     default:
  1742.     warn:
  1743.       fprintf (stderr,
  1744.            "warning: non standard mailer flag '%c' on line %d\n",
  1745.            c, line);
  1746.       sprintf(tstring, "/* unknown mailer flag: %c */", c);
  1747.       return tstring;
  1748.     }
  1749. }
  1750.  
  1751. #define doOundoc(val)    if (undoc) \
  1752. fprintf (stderr, "warning: undocumented option '%c' used on line %d\n", c, line);\
  1753. return (val)
  1754.  
  1755. /* optionname --- convert sendmail options to ease names */
  1756.  
  1757. char *optionname (c)
  1758. char c;
  1759. {
  1760.     static char buf[2] = { '\0', '\0' };
  1761.  
  1762.     switch (c) {
  1763.     case 'A':    return ("o_alias");
  1764.     case 'a':    return ("o_ewait");
  1765.     case 'B':    return ("o_bsub");
  1766.     case 'b':    return ("o_maxempty"); /* SunOS 4.0 */
  1767.     case 'C':    doOundoc ("o_checkpoint");
  1768.     case 'c':    return ("o_qwait");
  1769.     case 'd':    return ("o_delivery");
  1770.     case 'D':    return ("o_rebuild");
  1771.     case 'e':    return ("o_handling");
  1772.     case 'F':    return ("o_tmode");
  1773.     case 'f':    return ("o_usave");
  1774.     case 'g':    return ("o_gid");
  1775.     case 'H':    return ("o_fsmtp");
  1776.     case 'h':    return ("o_maxhops");    /* SunOS 4.0 */
  1777.     case 'i':    return ("o_skipd");
  1778.     case 'I':    return ("o_nameserver");    /* HP/UX */
  1779. /*    case 'K':        Keyed Database (IDA) */
  1780.     case 'L':    return ("o_slog");
  1781.     case 'm':    return ("o_rsend");
  1782.     case 'N':    return ("o_dnet");
  1783.     case 'n':    doOundoc ("o_validate");
  1784.     case 'o':    return ("o_hformat");
  1785.     case 'P':       doOundoc ("o_pmaster");
  1786.     case 'Q':    return ("o_qdir");
  1787.     case 'q':    docompat ("o_qfactor");
  1788.     case 'r':    return ("o_tread");
  1789.     case 'R':    return ("o_nfs");    /* SunOS 4.0 */
  1790.     case 'S':    return ("o_flog");
  1791.     case 's':    return ("o_safe");
  1792.     case 'T':    return ("o_qtimeout");
  1793.     case 't':    return ("o_timezone");
  1794.     case 'u':    return ("o_dmuid");
  1795.     case 'v':    return ("o_verbose");
  1796.     case 'W':    return ("o_wizpass");
  1797.     case 'x':    return ("o_loadq");
  1798.     case 'X':    return ("o_loadnc");
  1799.     case 'Y':    if (sunos ) return ("o_aliasfile"); else docompat ("o_newproc");
  1800.     case 'y':    docompat ("o_recipfactor");
  1801.     case 'z':    docompat ("o_prifactor");
  1802.     case 'Z':    docompat ("o_waitfactor");
  1803.     case '/':    return ("o_envelope");    /* IDA */
  1804.     default:
  1805.     warn:
  1806.         fprintf (stderr,
  1807.             "warning: Unknown option '%c' on line %d\n",
  1808.                 c, line);
  1809. /*        buf[0] = c; */
  1810.         return NULL;
  1811.     }
  1812. }
  1813.  
  1814. /* delivoption --- convert sendmail delivery option value to ease name */
  1815.  
  1816. char *delivoption (c)
  1817. char c;
  1818. {
  1819.     static char buf[2] = { '\0', '\0' };
  1820.  
  1821.     switch (c) {
  1822.     case 'i':    return ("d_interactive");
  1823.     case 'b':    return ("d_background");
  1824.     case 'q':    return ("d_queue");
  1825.     default:
  1826.         fprintf (stderr,
  1827.     "warning: non standard delivery option '%c' on line %d\n", c, line);
  1828.         return NULL;
  1829.     }
  1830. }
  1831.  
  1832. /* handle_option --- convert sendmail handling option value to ease name */
  1833.  
  1834. char *handle_option (c)
  1835. char c;
  1836. {
  1837.     static char buf[2] = { '\0', '\0' };
  1838.  
  1839.     switch (c) {
  1840.     case 'p':    return ("h_print");
  1841.     case 'q':    return ("h_exit");
  1842.     case 'm':    return ("h_mail");
  1843.     case 'w':    return ("h_write");
  1844.     case 'e':    return ("h_mailz");
  1845.     case '\0': 
  1846.         fprintf (stderr,
  1847.     "warning: value not specified for option on line %d\n", line);
  1848.         return NULL;
  1849.     default:
  1850.         fprintf (stderr,
  1851.     "warning: non standard handling option '%c' on line %d\n", c, line);
  1852.         return NULL;
  1853.     }
  1854. }
  1855.  
  1856. /*
  1857.  * "buffered" i/o routines. These are necessary since
  1858.  * mail headers may have continuation lines, and we can't see if
  1859.  * a continuation line is there without getting it. If it isn't,
  1860.  * just put it back.
  1861.  */
  1862.  
  1863. int saved = 0;
  1864. char *saveb = NULL;
  1865.  
  1866. /* ngets --- get a line of input from either saved buffer or stdin */
  1867.  
  1868. char *ngets (bp)
  1869. char *bp;
  1870. {
  1871.     if (! saved)
  1872.         return (gets (bp));
  1873.  
  1874.     saved = 0;
  1875.     bp = saveb;
  1876.     saveb = NULL;
  1877.     return (bp);
  1878. }
  1879.  
  1880. /* ungets --- put a buffer back on the input, so to speak */
  1881.  
  1882. void ungets (bp)
  1883. char *bp;
  1884. {
  1885.     saved = 1;
  1886.     saveb = bp;
  1887.     line--;
  1888. }
  1889.